/*************************************************
func: 封装socket客户端接口，实现tcp或udp通信
author: zyh
date: 2024.4
**************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>//提供IP地址转换函数
#include <sys/types.h>//数据类型定义文件
#include <sys/socket.h>//提供socket函数及数结构
//#include <netinet/in.h>//定义数据结构体sockaddr_in
//#include <netinet/ip.h>
#include <pthread.h>
#include "socket_api.h"
#include "socket_client_api.h"
 
/*socket客户端服务----------------------------------------*/
static void *socket_client_loop(void *ptr)
{
	int ret = 0;
    
	socket_client_t *client = (socket_client_t *)ptr;
    
	client->socket_fd = -1;
	if (IPPROTO_UDP == client->socket_protocol) {
        printf("start socket client (UDP) : -------------\n");
    } else {
        printf("start socket client (TCP): -------------\n");
    }
    if (0 < client->bind_port) {
        printf("bind_local_port:%d\n", client->bind_port);
    }
	printf("remote_ip:%s\n", client->remote_ip);
	printf("remote_port:%d\n\n", client->remote_port);
 
    
    int rcv_buf_size = (0 < client->rcv_buf_size) ? client->rcv_buf_size : 1024;
    //int rcv_flag = 0;
    int rcv_len = 0;
    unsigned char *rcv_buf = (unsigned char *)calloc(1, client->rcv_buf_size);
	if (!rcv_buf) {
		printf("calloc rcv_buf failed\n");
		goto done;
	}
    
    client->connect_flag = 0;
 
	while (client->run_flag) {
		if (0 == client->connect_flag) {//未连接
            if (0 < client->socket_fd) {
                close(client->socket_fd);
                client->socket_fd = -1;
            }
            client->socket_fd = socket_client_init(client->socket_type, client->socket_protocol, client->broadcast_flag, client->bind_port);
            if (0 > client->socket_fd) {
                sleep(1);
                printf("socket_client_init failed\n");
                continue;
            }
            
			//请求连接
			printf("socket client connect remote server (ip:%s port:%d)\n", client->remote_ip, client->remote_port);
            if (0 > socket_client_connect(client->socket_fd, client->remote_ip, client->remote_port)) {
                printf("socket_client_connect failed\n");
                if (0 < client->reconnect_time_s) {
                    sleep(client->reconnect_time_s);
                } else {
                    sleep(1);
                }
                continue;
            }
 
            //连接成功后再设置socket为非堵塞
            if (0 > set_fd_nonblock(client->socket_fd)) {
                printf("set_fd_nonblock failed\n");
                continue;
            }
            
			client->connect_flag = 1;//连接成功
			printf("socket_client_connect server succeeded\n");
			
			if (client->on_connect) {
				client->on_connect(client->socket_fd, client->arg);
			}
		} else {//连接成功，就进入内部监听消息
            ret = socket_rcv_nonblock(client->socket_fd, rcv_buf, rcv_buf_size - 1, 100);//超时100ms
            if (0 < ret) {// 处理接收到的数据
                //rcv_flag = 1;
                rcv_len = ret;
                rcv_buf[ret] = '\0';
                if (client->on_message) {
                    client->on_message(client->socket_fd, rcv_buf, rcv_len, client->arg);
                }
            } else if (0 == ret) {// 已经关闭了连接
                printf("socket disconnect\n");
				client->connect_flag = 0;
				if (client->on_disconnect) {
					client->on_disconnect(client->socket_fd, client->arg);
				}
            } else if (-1 == ret) {
                printf("socket_rcv_nonblock failed\n");
            }
		}
	}
    
done:
	//关闭释放资源
	client->connect_flag = 0;
	if (0 < client->socket_fd) {
        close(client->socket_fd);
        client->socket_fd = -1;
	}
	if (rcv_buf) {
        free(rcv_buf);
        rcv_buf = NULL;
	}
    
    printf("exit socket client\n");
    return NULL;
}
 
//启动一个socket客户端（这是一个线程服务）
int start_socket_client(socket_client_t *client)
{
	int ret = 0;
	ret = pthread_create(&client->thread_id, NULL, socket_client_loop, client);
	if (ret < 0) {
		printf("pthread_create socket_client_loop is failed\n");
		return -1;
	}
	client->run_flag = 1;
	return 0;
}
 
int close_socket_client(socket_client_t *client)
{
	if (client->run_flag) {
		client->run_flag = 0;
		pthread_join(client->thread_id, NULL);
	}
	
	return 0;
}
 
int restart_socket_client(socket_client_t *client)
{
    close_socket_client(client);
    return start_socket_client(client);
 
}
 